home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / diroutln.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-30  |  9.4 KB  |  343 lines

  1. unit DirOutln;
  2.  
  3. { Directory outline component }
  4.  
  5. interface
  6.  
  7. uses Classes, Forms, Controls, Outline, SysUtils, Graphics, Grids, StdCtrls,
  8.      Menus;
  9.  
  10. type
  11.   TTextCase = (tcLowerCase, tcUpperCase, tcAsIs);
  12.   TCaseFunction = function(const AString: string): string;
  13.  
  14.   TDirectoryOutline = class(TCustomOutline)
  15.   private
  16.     FDrive: Char;
  17.     FDirectory: TFileName;
  18.     FOnChange: TNotifyEvent;
  19.     FTextCase: TTextCase;
  20.     FCaseFunction: TCaseFunction;
  21.   protected
  22.     procedure SetDrive(NewDrive: Char);
  23.     procedure SetDirectory(const NewDirectory: TFileName);
  24.     procedure SetTextCase(NewTextCase: TTextCase);
  25.     procedure AssignCaseProc;
  26.     procedure BuildOneLevel(RootItem: Longint); virtual;
  27.     procedure BuildTree; virtual;
  28.     procedure BuildSubTree(RootItem: Longint); virtual;
  29.     procedure Change; virtual;
  30.     procedure Click; override;
  31.     procedure CreateWnd; override;
  32.     procedure Expand(Index: Longint); override;
  33.     procedure Loaded; override;
  34.     procedure WalkTree(const Dest: string);
  35.   public
  36.     constructor Create(AOwner: TComponent); override;
  37.     function ForceCase(const AString: string): string;
  38.     property Drive: Char  read FDrive write SetDrive;
  39.     property Directory: TFileName  read FDirectory write SetDirectory;
  40.     property Lines stored False;
  41.   published
  42.     property Align;
  43.     property BorderStyle;
  44.     property Color;
  45.     property Ctl3D;
  46.     property DragCursor;
  47.     property DragMode;
  48.     property Enabled;
  49.     property Font;
  50.     property ItemHeight;
  51.     property OnChange: TNotifyEvent  read FOnChange write FOnChange;
  52.     property OnClick;
  53.     property OnCollapse;
  54.     property OnDblClick;
  55.     property OnDragDrop;
  56.     property OnDragOver;
  57.     property OnDrawItem;
  58.     property OnEndDrag;
  59.     property OnEnter;
  60.     property OnExit;
  61.     property OnExpand;
  62.     property OnKeyDown;
  63.     property OnKeyPress;
  64.     property OnKeyUp;
  65.     property OnMouseDown;
  66.     property OnMouseMove;
  67.     property OnMouseUp;
  68.     property OnStartDrag;
  69.     property Options default [ooStretchBitmaps, ooDrawFocusRect];
  70.     property ParentColor;
  71.     property ParentCtl3D;
  72.     property ParentFont;
  73.     property ParentShowHint;
  74.     property PictureClosed;
  75.     property PictureLeaf;
  76.     property PictureOpen;
  77.     property PopupMenu;
  78.     property ScrollBars;
  79.     property Style;
  80.     property ShowHint;
  81.     property TabOrder;
  82.     property TabStop;
  83.     property TextCase: TTextCase  read FTextCase write SetTextCase default tcLowerCase;
  84.     property Visible;
  85.   end;
  86.  
  87. function SameLetter(Letter1, Letter2: Char): Boolean;
  88.  
  89.  
  90. implementation
  91.  
  92. const
  93.   InvalidIndex = -1;
  94.  
  95. constructor TDirectoryOutline.Create(AOwner: TComponent);
  96. begin
  97.   inherited Create(AOwner);
  98.   PictureLeaf := PictureClosed;
  99.   Options := [ooDrawFocusRect];
  100.   TextCase := tcLowerCase;
  101.   AssignCaseProc;
  102. end;
  103.  
  104. procedure TDirectoryOutline.AssignCaseProc;
  105. begin
  106.   case TextCase of
  107.     tcLowerCase: FCaseFunction := AnsiLowerCase;
  108.     tcUpperCase: FCaseFunction := AnsiUpperCase;
  109.     else FCaseFunction := nil;
  110.   end;
  111. end;
  112.  
  113. type
  114.   PNodeInfo = ^TNodeInfo;
  115.   TNodeInfo = record
  116.     RootName: TFileName;
  117.     SearchRec: TSearchRec;
  118.     DosError: Integer;
  119.     RootNode: TOutlineNode;
  120.     TempChild, NewChild: Longint;
  121.   end;
  122.  
  123. procedure TDirectoryOutline.BuildOneLevel(RootItem: Longint);
  124. var
  125.   NodeInfo: PNodeInfo;
  126. begin
  127.   New(NodeInfo);
  128.   try
  129.     with NodeInfo^ do
  130.     begin
  131.       RootName := Items[RootItem].FullPath;
  132.       if RootName[Length(RootName)] <> '\' then
  133.         RootName := Concat(RootName, '\');
  134.       RootName := Concat(RootName, '*.*');
  135.       DosError := FindFirst(RootName, faDirectory, SearchRec);
  136.       while DosError = 0 do
  137.       begin
  138.         if (SearchRec.Attr and faDirectory = faDirectory) and (SearchRec.Name[1] <> '.') then
  139.         begin
  140.           SearchRec.Name := ForceCase(SearchRec.Name);
  141.           RootNode := Items[RootItem];
  142.           if RootNode.HasItems then { if has children, must alphabetize }
  143.           begin
  144.             TempChild := RootNode.GetFirstChild;
  145.             while (TempChild <> InvalidIndex) and (Items[TempChild].Text < SearchRec.Name) do
  146.               TempChild := RootNode.GetNextChild(TempChild);
  147.             if TempChild <> InvalidIndex then
  148.               NewChild := Insert(TempChild, SearchRec.Name)
  149.             else NewChild := Add(RootNode.GetLastChild, SearchRec.Name);
  150.           end
  151.           else NewChild := AddChild(RootItem, SearchRec.Name); { if first child, just add }
  152.         end;
  153.         DosError := FindNext(SearchRec);
  154.       end;
  155.     end;
  156.     Items[RootItem].Data := Pointer(1); { make non-nil so we know we've been here }
  157.   finally
  158.     Dispose(NodeInfo);
  159.   end;
  160. end;
  161.  
  162. procedure TDirectoryOutline.BuildTree;
  163. begin
  164.   Clear;
  165.   AddChild(0, ForceCase(Drive + ':'));
  166.   WalkTree(FDirectory);
  167.   Change;
  168. end;
  169.  
  170. procedure TDirectoryOutline.BuildSubTree(RootItem: Longint);
  171. var
  172.   TempRoot: Longint;
  173.   RootNode: TOutlineNode;
  174. begin
  175.   BuildOneLevel(RootItem);
  176.   RootNode := Items[RootItem];
  177.   TempRoot := RootNode.GetFirstChild;
  178.   while TempRoot <> InvalidIndex do
  179.   begin
  180.     BuildSubTree(TempRoot);
  181.     TempRoot := RootNode.GetNextChild(TempRoot);
  182.   end;
  183. end;
  184.  
  185. procedure TDirectoryOutline.Change;
  186. begin
  187.   if Assigned(FOnChange) then FOnChange(Self);
  188. end;
  189.  
  190. procedure TDirectoryOutline.Click;
  191. begin
  192.   inherited Click;
  193.   Directory := Items[SelectedItem].FullPath;
  194. end;
  195.  
  196. procedure TDirectoryOutline.CreateWnd;
  197. var
  198.   CurrentPath: string;
  199. begin
  200.   inherited CreateWnd;
  201.   if FDrive = #0 then
  202.   begin
  203.     GetDir(0, CurrentPath);
  204.     FDrive := ForceCase(CurrentPath)[1];
  205.     FDirectory := ForceCase(CurrentPath);
  206.   end;
  207.   if (not (csLoading in ComponentState)) and
  208.     (csDesigning in ComponentState) then BuildTree;
  209. end;
  210.  
  211. procedure TDirectoryOutline.Expand(Index: Longint);
  212. begin
  213.   if Items[Index].Data = nil then { if we've not previously expanded }
  214.     BuildOneLevel(Index);
  215.   inherited Expand(Index); { call the event handler }
  216. end;
  217.  
  218. function TDirectoryOutline.ForceCase(const AString: string): string;
  219. begin
  220.   if Assigned(FCaseFunction) then
  221.     Result := FCaseFunction(AString)
  222.   else Result := AString;
  223. end;
  224.  
  225. procedure TDirectoryOutline.Loaded;
  226. begin
  227.   inherited Loaded;
  228.   AssignCaseProc;
  229.   BuildTree;
  230. end;
  231.  
  232. procedure TDirectoryOutline.SetDirectory(const NewDirectory: TFileName);
  233. var
  234.   TempPath: TFileName;
  235. begin
  236.   if Length(NewDirectory) > 0 then  { ignore empty directory }
  237.   begin
  238.     if (AnsiLastChar(NewDirectory) = ':') then
  239.       TempPath := ForceCase(NewDirectory)
  240.     else
  241.       TempPath := ForceCase(ExpandFileName(NewDirectory)); { expand to full path }
  242.     if (Length(TempPath) > 3) and (AnsiLastChar(TempPath) = '\') then
  243.       SetLength(TempPath, Length(TempPath) - 1);
  244.     if AnsiCompareFileName(TempPath, FDirectory) <> 0 then { is it a dir change? }
  245.     begin
  246.       FDirectory := TempPath; { set new directory }
  247.       ChDir(FDirectory); { go there }
  248.       if TempPath[1] <> Drive then { check to see if we changed drives, too }
  249.         Drive := TempPath[1] { change drive/build list if needed }
  250.       else
  251.       begin
  252.         if AnsiLastChar(FDirectory) <> ':' then
  253.           WalkTree(TempPath);
  254.         Change; { otherwise, we're done }
  255.       end;
  256.     end;
  257.   end;
  258. end;
  259.  
  260. procedure TDirectoryOutline.SetDrive(NewDrive: Char);
  261. var
  262.   TempPath: string;
  263. begin
  264.   if UpCase(NewDrive) in ['A'..'Z'] then { disallow all but drive letters}
  265.   begin
  266.     if (FDrive = #0) or not SameLetter(NewDrive, FDrive) then { update if no current drive or change }
  267.     begin
  268.       FDrive := NewDrive;
  269.       ChDir(FDrive + ':');
  270.       GetDir(0, TempPath);
  271.       FDirectory := ForceCase(TempPath); { use correct case }
  272.       if not (csLoading in ComponentState) then BuildTree; { this ends up calling Change }
  273.     end;
  274.   end;
  275. end;
  276.  
  277. procedure TDirectoryOutline.SetTextCase(NewTextCase: TTextCase);
  278. var
  279.   CurrentPath: string;
  280. begin
  281.   if NewTextCase <> FTextCase then
  282.   begin
  283.     FTextCase := NewTextCase;
  284.     AssignCaseProc;
  285.     if NewTextCase = tcAsIs then
  286.     begin
  287.       GetDir(0, CurrentPath);
  288.       FDrive := CurrentPath[1];
  289.       FDirectory := CurrentPath;
  290.     end;
  291.     if not (csLoading in ComponentState) then BuildTree;
  292.   end;
  293. end;
  294.  
  295. procedure TDirectoryOutline.WalkTree(const Dest: string);
  296. var
  297.   TempPath, NextDir: TFileName;
  298.   SlashPos: Integer;
  299.   TempItem: Longint;
  300.  
  301.   function GetChildNamed(const Name: string): Longint;
  302.   begin
  303.     Items[TempItem].Expanded := True;
  304.     Result := Items[TempItem].GetFirstChild;
  305.     while Result <> InvalidIndex do
  306.     begin
  307.       if Items[Result].Text = Name then Exit;
  308.       Result := Items[TempItem].GetNextChild(Result);
  309.     end;
  310.   end;
  311.  
  312. begin
  313.   TempItem := 1; { start at root }
  314.   TempPath := ForceCase(Dest);
  315.   if Pos(':', TempPath) > 0 then
  316.     TempPath := Copy(TempPath, Pos(':', TempPath) + 1, Length(TempPath));
  317.   if TempPath[1] = '\' then System.Delete(TempPath, 1, 1);
  318.   NextDir := TempPath;
  319.   while Length(TempPath) > 0 do
  320.   begin
  321.     SlashPos := Pos('\', TempPath);
  322.     if SlashPos > 0 then
  323.     begin
  324.       NextDir := Copy(TempPath, 1, SlashPos - 1);
  325.       TempPath := Copy(TempPath, SlashPos + 1, Length(TempPath));
  326.     end
  327.     else
  328.     begin
  329.       NextDir := TempPath;
  330.       TempPath := '';
  331.     end;
  332.     TempItem := GetChildNamed(NextDir);
  333.   end;
  334.   SelectedItem := TempItem;
  335. end;
  336.  
  337. function SameLetter(Letter1, Letter2: Char): Boolean;
  338. begin
  339.   Result := UpCase(Letter1) = UpCase(Letter2);
  340. end;
  341.  
  342. end.
  343.